/*
 * Copyright (c) 2017,安徽皖通科技股份有限公司 All rights reserved.
 */

package com.wttech.dzzf.process.service.upload;

import cn.com.taiji.common.manager.net.http.binclient.ApiRequestException;
import cn.com.taiji.sdk.comm.ETCCommHelper;
import cn.com.taiji.sdk.model.comm.protocol.AbstractSdtsRequest;
import cn.com.taiji.sdk.model.comm.protocol.AbstractSdtsResponse;
import cn.com.taiji.sdk.model.comm.protocol.user.VehicleUploadRequest;
import cn.com.taiji.sdk.tools.JsonTools;
import com.wttech.dzzf.process.constant.ExecuteTable;
import com.wttech.dzzf.process.constant.UserConstants;
import com.wttech.dzzf.process.dao.TransferUserInfoDao;
import com.wttech.dzzf.process.model.UploadRsp;
import com.wttech.dzzf.process.service.base.BaseInfoService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;

import static com.wttech.dzzf.process.constant.UserConstants.DEFAULT_SX_SENDER;

/**
 * 上传单一数据服务
 *
 * @author MaShibo
 * @date 2017/12/11.
 */
@Service
public class UploadSingleDataService {

	@Resource
	private TransferUserInfoDao transferUserInfoDao;

	@Resource
	private ThreadPoolTaskExecutor executor;

	@Resource
	private BaseInfoService baseInfoService;

	/**
	 * 单次处理数量
	 */
	private int processNum;

	private static final Logger LOGGER = LoggerFactory.getLogger(UploadSingleDataService.class);

	void uploadThread(ExecuteTable table, int num) {
		LOGGER.info("第{}次，开始执行...", num);
		int startRow = (num - 1) * processNum + 1;
		int endRow = num * processNum;
		List<? extends AbstractSdtsRequest> infos = transferUserInfoDao.queryUseriInfoRecord(table.getTableName(), table.getRequestType(),
				startRow, endRow);
		infos.forEach(info -> uploadSdtsInfo(info, table, false));
		LOGGER.info("第{}次，结束执行...", num);
	}

	void uploadSingleQuery(ExecuteTable table, int total) {
		List<? extends AbstractSdtsRequest> infos = transferUserInfoDao.queryUseriInfoRecord(table.getTableName(), table.getRequestType(),
				1, total);
		List<Future<Void>> futures = new ArrayList<>(total);
		infos.forEach(info -> futures.add(executor.submit(() -> {
			uploadSdtsInfo(info, table, false);
			return null;
		})));
		baseInfoService.getFutureResult(futures);
	}

	public boolean uploadSdtsInfo(AbstractSdtsRequest request, ExecuteTable table, boolean isRepeat) {

		boolean isVehicle = request instanceof VehicleUploadRequest;
		try {
			AbstractSdtsResponse response = ETCCommHelper.upload(request.getFileName(DEFAULT_SX_SENDER), request,
					table.getResponseType());
			String infoId = null;
			if (isVehicle) {
				VehicleUploadRequest vehicle = (VehicleUploadRequest) request;
				transferUserInfoDao.updateVehicleFlag(vehicle.getId(), vehicle.getUserId(), UploadRsp.SUCCESS);
			} else {
				infoId = getPropertyValue(request);
				updateUploadFlag(table.getTableName(), infoId, UploadRsp.SUCCESS);
			}

			//是否重传
			if (isRepeat) {
				if (isVehicle) {
					VehicleUploadRequest vehicle = (VehicleUploadRequest) request;
					infoId = vehicle.getId() + "+" + vehicle.getUserId();
				}
				deleteFailureLog(infoId, table.getStorePath());
			}

			LOGGER.info("响应消息{}，响应时间{}", response.getInfo(), response.getReceiveTime());
		} catch (Exception e) {
			try {
				recordFailture(request, e, table, isVehicle);
				if (e instanceof IOException) {
					uploadSdtsInfo(request, table, isRepeat);
				}
				return false;
			} catch (Exception e1) {
				LOGGER.error(e1.getMessage(), e1);
			}
		}
		return true;
	}

	public <T extends AbstractSdtsResponse> void upload(AbstractSdtsRequest request, Class<T> cls) {
		try {
			ETCCommHelper.upload(request.getFileName(UserConstants.DEFAULT_SX_SENDER), request, cls);
		} catch (IOException e) {
			LOGGER.error(e.getMessage());
			upload(request, cls);
		} catch (ApiRequestException e) {
			recordFailture(request, e, ExecuteTable.OBU, request instanceof VehicleUploadRequest);
		}

	}


	private void recordFailture(AbstractSdtsRequest request, Exception e, ExecuteTable table, boolean isVehicle) {
		//记录失败信息
		String type = table.getStorePath();
		String infoId = getPropertyValue(request);

		if (isVehicle) {
			VehicleUploadRequest vehicle = (VehicleUploadRequest) request;
			infoId = infoId + "+" + vehicle.getUserId();
		}
		if (transferUserInfoDao.queryUploadRspNum(infoId, type) > 0) {
			transferUserInfoDao.deleteUploadRsp(infoId, type);
		}
		UploadRsp uploadRsp = new UploadRsp();
		String requestInfo = null;
		try {
			requestInfo = JsonTools.toJsonStr(request);
		} catch (IOException e1) {
			LOGGER.error(e1.getMessage(), e1);
		}

		boolean isIOError = e instanceof IOException;
		if (isIOError) {
			LOGGER.error("网络异常：{}", e.getMessage());
			uploadRsp.setErrorMessage(e.getMessage());
		} else if (e instanceof ApiRequestException) {
			uploadRsp.setErrorCode(((ApiRequestException) e).getErrCode());
			uploadRsp.setErrorMessage(e.getMessage());
		} else {
			LOGGER.error(e.getMessage(), e);
			uploadRsp.setErrorMessage(e.getMessage());
		}
		uploadRsp.setRequest(requestInfo);
		uploadRsp.setType(table.getStorePath());
		uploadRsp.setInfoId(infoId);
		uploadRsp.setCreateOn(new Date());
		transferUserInfoDao.createTestObjcet(uploadRsp);
		//更新上传状态
		if (isVehicle) {
			VehicleUploadRequest vehicle = (VehicleUploadRequest) request;
			transferUserInfoDao.updateVehicleFlag(vehicle.getId(), vehicle.getUserId(), UploadRsp.FAILTURE);
		} else {
			updateUploadFlag(table.getTableName(), infoId, UploadRsp.FAILTURE);
		}
	}

	private String getPropertyValue(AbstractSdtsRequest request) {
		String infoId = null;
		try {
			Method getMethod = request.getClass().getDeclaredMethod("get" + "Id");
			infoId = getMethod.invoke(request).toString();
		} catch (Exception e2) {
			LOGGER.error(e2.getMessage(), e2);
		}
		return infoId;
	}


	private void updateUploadFlag(String tableName, String id, int flag) {
		try {
			transferUserInfoDao.updateUploadFlag(id, tableName, flag);
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
	}

	private void deleteFailureLog(String infoId, String type) {
		try {
			transferUserInfoDao.deleteFailureLog(infoId, type);
		} catch (Exception e) {
			LOGGER.error("未删除INFOID【{}】类型【{}】", infoId, type);
			LOGGER.error(e.getMessage(), e);
		}
	}

	void setProcessNum(int processNum) {
		this.processNum = processNum;
	}
}
